package com.rockcent.api.net;

import android.text.TextUtils;
import android.util.Log;

import com.google.gson.Gson;
import com.rockcent.api.utils.EncryptUtil;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * 描述信息
 *
 * @author keegan
 * @date 15/8/21
 */
public class HttpEngine {
    private final static String APP_KEY = "ANDROID_LEMON_XYSQ";
    private final static String APP_SECRET = "aa5f6e9c5ee7e0a206a8da259ceda409ba935f2d417c7891";
    private final static String REQUEST_METHOD = "POST";
    private final static String CONTENT_TYPE = "application/x-www-form-urlencoded;charset=UTF-8";
    private final static String ENCODE_TYPE = "UTF-8";
    private final static int TIME_OUT = 20000;

    private String serverUrl;

    public HttpEngine(String serverUrl) {
        this.serverUrl = serverUrl;
    }

    public <T> T postHandle(Map<String, Object> paramsMap, Type typeOfT) throws Exception {
        return postHandle(paramsMap, typeOfT, null);
    }

    public <T> T postHandle(Map<String, Object> paramsMap, Type typeOfT, String urlSuffix) throws Exception {
        paramsMap.put("appKey", APP_KEY);
        paramsMap.put("sign", signHandle(map2Pair(paramsMap)));
        String data = joinParams(paramsMap);
        if (TextUtils.isEmpty(urlSuffix)) {
            // 打印出请求
            Log.e("request:", serverUrl + "?" + data);
        } else {
            // 打印出请求
            Log.e("request:", serverUrl + urlSuffix + "?" + data);
        }

        HttpURLConnection connection = getConnection(TextUtils.isEmpty(urlSuffix) ? serverUrl : serverUrl + urlSuffix);
        connection.setRequestProperty("Content-Length", String.valueOf(data.getBytes().length));
        connection.connect();
        OutputStream os = connection.getOutputStream();
        os.write(data.getBytes());
        os.flush();
        // 获取响应的输入流对象
        InputStream is = connection.getInputStream();
        // 创建字节输出流对象
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 定义读取的长度
        int len = 0;
        // 定义缓冲区
        byte buffer[] = new byte[1024];
        // 按照缓冲区的大小，循环读取
        while ((len = is.read(buffer)) != -1) {
            // 根据读取的长度写入到os对象中
            baos.write(buffer, 0, len);
        }
        // 释放资源
        is.close();
        baos.close();
        connection.disconnect();
        // 返回字符串
        final String result = new String(baos.toByteArray());
        Log.i("response:", result);

        if (connection.getResponseCode() == 200) {
            Gson gson = new Gson();
            return gson.fromJson(result, typeOfT);
        } else {
            connection.disconnect();
            return null;
        }
    }

    // 获取connection
    private HttpURLConnection getConnection(String urlString) {
        HttpURLConnection connection = null;
        // 初始化connection
        try {
            // 根据地址创建URL对象
            URL url = new URL(urlString);
            // 根据URL对象打开链接
            connection = (HttpURLConnection) url.openConnection();
            // 设置请求的方式
            connection.setRequestMethod(REQUEST_METHOD);
            // 发送POST请求必须设置允许输入，默认为true
            connection.setDoInput(true);
            // 发送POST请求必须设置允许输出
            connection.setDoOutput(true);
            // 设置不使用缓存
            connection.setUseCaches(false);
            // 设置请求的超时时间
            connection.setReadTimeout(TIME_OUT);
            connection.setConnectTimeout(TIME_OUT);
            connection.setRequestProperty("Content-Type", CONTENT_TYPE);
            connection.setRequestProperty("Connection", "keep-alive");
            connection.setRequestProperty("Response-Type", "json");
            connection.setChunkedStreamingMode(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return connection;
    }

    // 拼接参数列表
    private String joinParams(Map<String, Object> paramsMap) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : paramsMap.keySet()) {
            stringBuilder.append(key);
            stringBuilder.append("=");
            try {
                stringBuilder.append(URLEncoder.encode(paramsMap.get(key).toString(), ENCODE_TYPE));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            stringBuilder.append("&");
        }
        return stringBuilder.substring(0, stringBuilder.length() - 1);
    }

    private List<NameValuePair> map2Pair(Map<String, Object> paramsMap) {
        List<NameValuePair> pairList = new ArrayList<NameValuePair>();
        for (String key : paramsMap.keySet()) {
            pairList.add(new BasicNameValuePair(key, paramsMap.get(key).toString()));
        }
        return pairList;
    }

    // 签名处理
    private String signHandle(List<NameValuePair> params) throws NoSuchAlgorithmException,
            UnsupportedEncodingException {
        // 所有请求参数按参数名升序排序
        PairComparator comparator = new PairComparator();
        Collections.sort(params, comparator);
        // 按请求参数名和参数值相互连接组成一个字符串
        // 以及头尾添加KEY_SECRET
        StringBuilder stringBuffer = new StringBuilder(APP_SECRET);
        for (NameValuePair pair : params) {
            stringBuffer.append(pair.getName()).append(pair.getValue());
        }
        stringBuffer.append(APP_SECRET);
        // SHA1加密
        String sign = EncryptUtil.makeSHA1(stringBuffer.toString());
        // 添加签名
        params.add(new BasicNameValuePair("sign", sign));
        return sign;
    }

    private class PairComparator implements Comparator<NameValuePair> {

        @Override
        public int compare(NameValuePair lhs, NameValuePair rhs) {
            return lhs.getName().compareTo(rhs.getName());
        }

    }
}
